package name.cyl.parseXml;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import name.cyl.parseXml.dto.RootData;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public final class ParseXmlServices {
	private static final SAXParserFactory SAX_PARSER_FACTORY=SAXParserFactory.newInstance();
	private static final JAXBContext ROOT_DATA_JAXB_CONTEXT=createRootDataJaxbContext();
	
	public static final Map<String, Object> parseXmlToMap(InputStream inputStream){
		try {
			SAXParser saxParser = SAX_PARSER_FACTORY.newSAXParser();
			Map<String, Object> map=new HashMap<String, Object>();
			saxParser.parse(inputStream, new XmlToMapHandler(map));
			return map;
		} catch (ParserConfigurationException e) {
			throw new RuntimeException(e);
		} catch (SAXException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static final RootData parseTestData(InputStream inputStream){
		try {
			Unmarshaller unmarshaller=ROOT_DATA_JAXB_CONTEXT.createUnmarshaller();
			Object result=unmarshaller.unmarshal(inputStream);
			return (RootData)result;
		} catch (JAXBException e) {
			throw new RuntimeException(e);
		}
	}
	
	private static JAXBContext createRootDataJaxbContext(){
		try {
			JAXBContext context=JAXBContext.newInstance(RootData.class);
			return context;
		} catch (JAXBException e) {
			throw new RuntimeException(e);
		}
	}
}

final class XmlToMapHandler extends DefaultHandler{
	private final LinkedList<Object> stack=new LinkedList<Object>();
	private final Map<String, Object> resultMap;
	private final StringBuilder elementCharacter=new StringBuilder();
	
	public XmlToMapHandler(Map<String, Object> map){
		resultMap=map;
	}

	@Override
	public void startDocument() throws SAXException {
		super.startDocument();
	}

	@Override
	public void endDocument() throws SAXException {
		super.endDocument();
	}

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		switch (stack.size()) {
		case 0:
			stack.push(qName);
			break;
		case 1:
			stack.push(qName);
			elementCharacter.setLength(0);
			break;
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		switch (stack.size()) {
		case 1:
			stack.pop();
			break;
		case 2:
			stack.pop();
			resultMap.put(qName, elementCharacter.toString());
			break;
		}
	}

	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		elementCharacter.append(ch,start,length);
	}

	@Override
	public void error(SAXParseException e) throws SAXException {
		e.printStackTrace();
	}

	@Override
	public void fatalError(SAXParseException e) throws SAXException {
		e.printStackTrace();
	}
	
	
}